package common;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.StringTokenizer;
import java.util.TreeMap;

/**
 * Représente un modèle Multinomial pour associer à chaque mot, chaque classe (positive ou
 * negative) un paramètre Béta.
 * Ce paramètre Beta est obtenu grace à l'association entre Mot,Classe,Nb Occurences
 * du mot dans tous les documents de la classe.
 * Il suffit alors, pour trouver un paramètre Béta, de faire le ratio :
 * 			
 * 			Béta(Mot,Classe) = (Nb Occurences du mot dans tous les documents de la classe)
 * 															
 * 															/
 * 								
 * 								(Nb Occurences de TOUS les mots de tous les documents de la classe)
 * 
 * Ce modèle Multinomial prend donc en compte le nombre d'occurences total d'un mot dans
 * les documents d'une classe, ce qui permet de ne pas se restreindre à une seule occurence
 * (au maximum) du mot par document.
 * @author franck
 *
 */
public class CMultinomial {

	protected ArrayList<File> listeFichiersApprentissage = new ArrayList<File>();
	protected File FichierTest;
	protected boolean sauvegarderDictionnaires;

	/**
	 * Suppression ou non des mots outils
	 */
	// 1ER paramètre entrant en compte dans l'optimisation du programme
	protected static boolean SUPPRESSIONMOTSOUTILS;

	// La liste de mots outils, vide ou non, selon la valeur de la variable booléenne
	// précédente
	protected ArrayList<String> listeMotsOutils;

	/**
	 * Création dictionnaire, à partir du fichier d'apprentissage
	 */

	// On désigne comme Pattern de début de critique :
	// une ligne commençant par une balise ouvrante "<review" suivie d'un espace,
	// puis de "id='" pour déclarer son identifiant, suivi d'un nombre et de "'" pour fermer
	// l'attribut id, puis d'un espace, suivi de "class=', avec un ensemble de caractères,
	// suivi de "'" pour fermer l'attribut class, et enfin d'un chevron fermant ">".
	// les "\\s*" servent à reconnaitre cette ligne particulière, même s'il y'avait
	// des espaces placés avant, après ou à l'intérieur de la balise <review>.
	protected Pattern debutCritiquePattern = Pattern.compile("\\s*<review\\s* id='((\\d)+)'\\s* class='((\\w)+)'\\s*>\\s*");

	// De m�me, on d�signe le Pattern de fin de critique :
	// une ligne contenant la balise fermante "</review>", avec (ou non) des espaces
	// plac�s avant ou apr�s cette balise de fermeture.
	protected Pattern finCritiquePattern = Pattern.compile("\\s*</review>\\s*");

	// Map : Association <mot, nbOccurences dans le corpus>, 
	// en filtrant les mots outils (si on le souhaite)
	protected Map<String,Integer> dictionnaire; 

	// Un map associant : pour chaque mot, pour chaque classe, le nombre d'occurences
	// total du mot dans tous les documents de la classe
	protected Map <String, Map<String,Double>> motCategorieNbOcc;

	// La cat�gorie de la critique courante ("positive" ou "negative")
	protected String categorieCritiqueCourante;

	// La probabilité courante de la critique, en association avec la polarité
	// (polarité certaine ou supposée)
	protected double probabiliteCritiqueCourante;


	/**
	 * Filtrage du dictionnaire, � partir d'un seuil de fr�quence maximal
	 */

	// Seuil de fréquence maximum
	// 2EME paramètre entrant en compte dans l'optimisation du programme
	protected static double SEUIL_FREQUENCE_MAXI;

	// Map : mot, nbOcc en filtrant la fr�quence des mots

	protected Map<String,Integer> dictionnaireFiltre;	

	// En ayant filtré avec le seuil de fréquence
	protected Map <String, Map<String,Double>> motCategorieNbOccFiltre;

	/**
	 * Sauvegarde du dictionnaire, du dictionnaire avec nbOcc décroissant,
	 * et de la correspondance Mot,Categorie,NbDocs
	 */

	// Si un mot n'apparait aucune fois dans une cat�gorie particuli�re (positive, n�gative,
	// ou ni l'une ni l'autre), on ajoutera une constante EPSILON au num�rateur, et
	// EPSILON * Nombre de mots dictionnaire filtr� au d�nominateur, dans le calcul
	// du paramètre Béta(mot,classe)
	protected static double EPSILON;

	/**
	 * Cr�ation et sauvegarde de Mot,Categorie,Paramètre
	 */

	// Map permettant d'associer à une catégorie (positive ou negative) le nombre total
	// de mots contenus dans tous les documents de cette catégorie
	protected Map <String, Double> categorieNbMotsDansToutesLesCritiquesDeLaCategorie;

	// Le map qui contiendra pour chaque mot, chaque catégorie, un paramètre Beta
	// associé
	protected Map <String, Map<String,Double>> motCategorieParametre;

	/**
	 * Classification et détermination du taux de réussite
	 */

	// Nombre de bonnes prédictions de classe pour un fichier Test
	protected int nbDecisionsCorrectesPourUnJeuDeTest;

	// Nombre de critiques contenues dans le fichier Test
	protected int nbCritiquesJeuDeTestCourant;

	// Taux de réussite dans les prédictions
	protected double tauxReussite;

	/**
	 * Pour afficher des statistiques
	 */

	// Nombre total de critiques dans le fichier d'apprentissage
	protected int nbCritiques;

	// Nombre de mots total contenu dans le fichier d'apprentissage (sans les mots outils)
	protected int nbMotsDuCorpus;

	// Le nombre de critiques positives, négatives
	// Utile pour déterminer le paramètre de chaque mot, chaque catégorie
	protected int nbCritiquesPositives;
	protected int nbCritiquesNegatives;

	public CMultinomial() {}

	/**
	 * Une instance de la classe ModeleMultinomial permet de créer un modèle, en se basant
	 * sur les informations contenues dans un fichier d'apprentissage "FicApp", pour pouvoir
	 * essayer de classifier les critiques contenues dans le fichier "FicTest".
	 * @param FicApp	le fichier d'apprentissage, contenant des critiques labellisées
	 * @param FicTest	le fichier de test, contenant des critiques dont la classe
	 * (positive ou negative) est à prédire
	 * @param suppression	permet d'enlever les mots outils (true) ou pas (false)
	 * @param seuil			correspond au seuil de fréquence maximal au-delà duquel les mots
	 * 						du vocabulaire initial ne seront pas retenus
	 * @param epsilon		constante de Laplace que l'on ajoute au numérateur, dans le calcul
	 * 						du Béta(Mot,Classe) pour éviter d'avoir des paramètres Béta
	 * 						égaux à 0. (epsilon > 1)
	 */
	public CMultinomial(ArrayList<File> fichiersAp, File FicTest,boolean suppression,
			double seuil, double epsilon, boolean saveDic){

		// ------------------------------------------
		// Initialisation des param�tres pouvant influer l'estimation du jeu de test
		// ------------------------------------------

		SUPPRESSIONMOTSOUTILS = suppression;
		SEUIL_FREQUENCE_MAXI = seuil;
		EPSILON = epsilon;

		/**
		 * Initialisation de l'ensemble des variables utilisées
		 */

		listeFichiersApprentissage = fichiersAp;
		FichierTest = FicTest;
		sauvegarderDictionnaires = saveDic;
		
		for(File f : listeFichiersApprentissage){
			System.out.println("(Classifieur Multinomial) Fichier apprentissage :" + f.getAbsolutePath());
		}
		System.out.println("(Classifieur Multinomial) Fichier Test : " + FichierTest.getAbsolutePath());
		 


		listeMotsOutils = new ArrayList<String>();
		dictionnaire = new TreeMap<String, Integer>();

		motCategorieNbOcc = new TreeMap<String, Map<String,Double>>();

		dictionnaireFiltre = new TreeMap<String, Integer>();

		motCategorieNbOccFiltre = new TreeMap<String, Map<String,Double>>();

		categorieNbMotsDansToutesLesCritiquesDeLaCategorie = new TreeMap<String, Double>();

		motCategorieParametre = new TreeMap<String, Map<String,Double>>();


		nbDecisionsCorrectesPourUnJeuDeTest = 0;
		nbCritiquesJeuDeTestCourant = 0;

		tauxReussite = 0.0;


		nbCritiques = 0;
		nbMotsDuCorpus = 0;

		nbCritiquesPositives = 0;
		nbCritiquesNegatives = 0;

		//executerCreationClasseur();
	}

	public File getFichierTest() {
		return FichierTest;
	}

	public void setFichierTest(File fichierTest) {
		FichierTest = fichierTest;
	}

	public double getTauxReussite() {
		return tauxReussite;
	}

	public void setTauxReussite(double tauxReussite) {
		this.tauxReussite = tauxReussite;
	}

	public void executerCreationClasseur() {

		debutApprentissage();		
		evaluationJeuTest();	
	}

	public void debutApprentissage(){

		// ------------------------------------------
		// D�but de l'apprentissage
		// ------------------------------------------

		if (SUPPRESSIONMOTSOUTILS) suppressionMotsOutils();

		creationDictionnaire();

		// Affichage de quelques statistiques (le nombre de mots
		// peut varier selon les valeurs des paramètres considérés)
		
		System.out.println("Nb Critiques : " + nbCritiques);
		System.out.println("Nb positives : " + nbCritiquesPositives);
		System.out.println("Nb negatives: " + nbCritiquesNegatives);
		//System.out.println("Nb Mots du (des) corpus : " + nbMotsDuCorpus);
		 
		filtrageDictionnaireSeuilMaximum();

		//System.out.println("Taille dictionnaire filtré : " + dictionnaireFiltre.size());

		if (sauvegarderDictionnaires){
			sauverDictionnaire();			
		}
		sauverMotsPlusFrequentsDictionnaire();
		sauverMotCategorieNbDocs();
		creerEtSauvegarderMotCategorieParametre();

	}

	public void evaluationJeuTest(){

		// ------------------------------------------
		// 2ème étape (et 3ème étape) : évaluation d'un jeu de test, par rapport à
		// un jeu d'apprentissage
		// ------------------------------------------

		classification();

		tauxReussite = (double)nbDecisionsCorrectesPourUnJeuDeTest/(double)nbCritiquesJeuDeTestCourant;
		System.out.println("(Classifieur Multinomial) Taux de réussite = "+tauxReussite);

		sauverTauxReussite();	

	}
	/**
	 * construit listeMotsOutils : liste de mots outils
	 * @param suppression
	 */
	public void suppressionMotsOutils() {
		// Si on souhaite supprimer les mots-outils, alors on va ouvrir le
		// fichier "mots_outils.txt" et ajouter chacun des mots dans la liste
		// de mots outils

		try {
			// On ouvre le fichier mot_outils.txt
			BufferedReader lecteur = new BufferedReader(new FileReader("mots_outils/mots_outils.txt"));
			String ligne;

			// Pour chaque ligne trouvée...
			while((ligne = lecteur.readLine()) != null){
				// Si cette ligne contient autre chose qu'un blanc, on l'ajoute à la liste
				if(!ligne.isEmpty()){
					listeMotsOutils.add(ligne);
				}
			}
		}
		catch(Exception e){
			e.printStackTrace();
		}

	}

	public void creationDictionnaire(){

		// On récupère les critiques du fichier d'apprentissage
		ArrayList<Critique> lesCritiques = determinerLesCritiques(listeFichiersApprentissage);
		//	System.out.println("Nb critiques des fichiers d'apprentissage : " +	lesCritiques.size());

		// Pour chaque critique du fichier d'apprentissage
		for(int j = 0; j < lesCritiques.size(); j++){


			probabiliteCritiqueCourante = lesCritiques.get(j).getProbabilite();

			// Si le fichier courant est une critique positive
			if(lesCritiques.get(j).getTypeCritique().equals("positive")){
				categorieCritiqueCourante = "positive";
				nbCritiquesPositives++;
			}
			// Si le fichier courant est une critique négative
			else {
				categorieCritiqueCourante = "negative";
				nbCritiquesNegatives++;
			}

			analyseCritique(lesCritiques.get(j).getContenu());
			nbCritiques++;

			/*	System.out.println("=============================");
			System.out.println("Critique numero : " + lesCritiques.get(j).getIdentifiant());
			System.out.println("Type :  " + lesCritiques.get(j).getTypeCritique());
			System.out.println(lesCritiques.get(j).getContenu());
			System.out.println("=============================");*/
		}
	}

	public ArrayList<Critique> determinerLesCritiques(File fichier) {

		ArrayList<Critique> lesCritiquesARenvoyer = new ArrayList<Critique>();


		BufferedReader lecteur = null;
		try {
			lecteur = new BufferedReader(new FileReader(fichier));
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		String ligne;

		int identifiantCourant = 0;
		String unTypeCritique = "";
		String unContenuCritique = "";

		try {
			while((ligne = lecteur.readLine()) != null){
				Matcher mDebut = debutCritiquePattern.matcher(ligne);
				Matcher mFin = finCritiquePattern.matcher(ligne);

				// Début d'une critique, on récupère identifiant et classe
				if(mDebut.matches()){

					String [] lesMorceauxDeLaLigne = ligne.split("'");
					identifiantCourant = Integer.valueOf(lesMorceauxDeLaLigne[1]);
					unTypeCritique = lesMorceauxDeLaLigne[3];
				}
				// Fin de critique, on remet le contenuCritique à "" et on crée une
				// nouvelle ligne
				else if(mFin.matches()){

					lesCritiquesARenvoyer.add(new Critique(identifiantCourant,unTypeCritique,unContenuCritique));
					unContenuCritique = "";
				}
				// Contenu d'une critique qu'on ajoute
				else {
					unContenuCritique += ligne;
				}
			}
		} catch (NumberFormatException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}


		return lesCritiquesARenvoyer;
	}

	public ArrayList<Critique> determinerLesCritiques(ArrayList<File> listeFichiers)  {

		ArrayList<Critique> lesCritiquesARenvoyer = new ArrayList<Critique>();

		for (File f : listeFichiers){


			BufferedReader lecteur = null;
			try {
				lecteur = new BufferedReader(new FileReader(f));
			} catch (FileNotFoundException e) {

				e.printStackTrace();
			}
			String ligne;

			int unIdentifiant = 0;
			String unTypeCritique = "";
			String unContenuCritique = "";
			double probabilite = 0.0;

			try {
				while((ligne = lecteur.readLine()) != null){
					Matcher mDebut = debutCritiquePattern.matcher(ligne);
					Matcher mFin = finCritiquePattern.matcher(ligne);

					// Début d'une critique, on récupère identifiant et classe
					if(mDebut.matches()){

						String [] lesMorceauxDeLaLigne = ligne.split("'");
						unIdentifiant = Integer.valueOf(lesMorceauxDeLaLigne[1]);

						if(!lesMorceauxDeLaLigne[3].contains(":")){
							unTypeCritique = lesMorceauxDeLaLigne[3];
							probabilite = 1.0;
						}
						else {
							unTypeCritique = lesMorceauxDeLaLigne[3].split(":")[0];
							probabilite = Double.valueOf(lesMorceauxDeLaLigne[3].split(":")[1]);
						}

					}
					// Fin de critique, on remet le contenuCritique à "" et on crée une
					// nouvelle ligne
					else if(mFin.matches()){

						lesCritiquesARenvoyer.add(new Critique(unIdentifiant,unTypeCritique,unContenuCritique,probabilite));
						unContenuCritique = "";
					}
					// Contenu d'une critique qu'on ajoute
					else {
						unContenuCritique += ligne;
					}
				}
			} catch (NumberFormatException e) {

				e.printStackTrace();
			} catch (IOException e) {

				e.printStackTrace();
			}
		}


		return lesCritiquesARenvoyer;
	}

	public void analyseCritique(String contenuCritique) {

		StringTokenizer tokeniseur = new StringTokenizer(contenuCritique, " ");

		// Pour chaque mot trouvé sur la ligne...
		while (tokeniseur.hasMoreTokens()) {
			String unMot = tokeniseur.nextToken();

			//System.out.println("Mot analysé : " + unMot);
			// Si ce n'est pas un mot outil, ni un nombre...
			if(!listeMotsOutils.contains(unMot) && unMot.matches("[a-zA-Z]*")){

				// On incr�mente le nombre de mots utiles du corpus (sans mots outils)
				nbMotsDuCorpus++;

				// Si le dictionnaire contient déjà le mot, on incrémente son nombre
				// d'occurences précédent
				if(dictionnaire.containsKey(unMot)){
					dictionnaire.put(unMot, (int) (dictionnaire.get(unMot)+ probabiliteCritiqueCourante));
				}
				else {
					// Sinon on crée une nouvelle entrée dans le TreeMap, avec comme nb
					// d'occurences initial "1"

					dictionnaire.put(unMot, (int) probabiliteCritiqueCourante);

				}

				//System.out.println("Mot : " + unMot + " n'existe pas deja dans fic courant");
				if(motCategorieNbOcc.containsKey(unMot)){
					// ... S'il y'a déjà une entrée pour le mot, et la catégorie en cours...
					if(motCategorieNbOcc.get(unMot).containsKey(categorieCritiqueCourante)){
						motCategorieNbOcc.get(unMot).put(categorieCritiqueCourante, motCategorieNbOcc.get(unMot).get(categorieCritiqueCourante) + probabiliteCritiqueCourante);
					}
					// ... sinon ...
					else {
						motCategorieNbOcc.get(unMot).put(categorieCritiqueCourante, (double) probabiliteCritiqueCourante);
					}
				}
				else {
					TreeMap<String, Double> categorieNbCritiques = new TreeMap<String, Double>();
					categorieNbCritiques.put(categorieCritiqueCourante, (double) probabiliteCritiqueCourante);
					motCategorieNbOcc.put(unMot, categorieNbCritiques);
				}

			}
		}
	}

	public void filtrageDictionnaireSeuilMaximum() {

		for (String motCourant : dictionnaire.keySet()){
			if((((double)dictionnaire.get(motCourant) / nbMotsDuCorpus) < SEUIL_FREQUENCE_MAXI)){
				dictionnaireFiltre.put(motCourant, dictionnaire.get(motCourant));
				motCategorieNbOccFiltre.put(motCourant, motCategorieNbOcc.get(motCourant));
			}
		}
	}
	public void sauverDictionnaire() {
		System.out.println("Sauvegarde du dictionnaire");
		PrintWriter ecrivain = null;

		try {
			ecrivain =  new PrintWriter(new BufferedWriter
					(new FileWriter("dictionnaireTrieParMot.txt")));
		} catch (IOException e) {

			e.printStackTrace();
		}

		for (Entry<String, Integer> entreeCourante : dictionnaireFiltre.entrySet()){
			ecrivain.println("Mot : " + entreeCourante.getKey() + ", Nb Occ : " 
					+ entreeCourante.getValue());
		}
		ecrivain.close();
	}

	public void sauverMotsPlusFrequentsDictionnaire() {
		//System.out.println("Sauve mots les plus fréquents");

		List<Map.Entry<String, Integer>> list = new ArrayList<Map.Entry<String, Integer>>(dictionnaireFiltre.entrySet());
		Collections.sort(list, new Comparator<Map.Entry<String, Integer>>() {

			@Override
			public int compare(Entry<String,Integer> o1,
					Entry<String, Integer> o2) {
				return (o2.getValue().compareTo(o1.getValue()));
			}
		});
		if (sauvegarderDictionnaires){

			PrintWriter ecrivain = null;

			try {
				ecrivain =  new PrintWriter(new BufferedWriter
						(new FileWriter("dictionnaireTrieParNbOccDecroissant.txt")));
			} catch (IOException e) {

				e.printStackTrace();
			}

			for(Entry<String, Integer> entreeCourante : list){
				//System.out.println("J'écris le mot " + entreeCourante.getKey() + " dans le fichier");
				ecrivain.println("Mot : " + entreeCourante.getKey() + ", Nb Occ : " 
						+ entreeCourante.getValue());
			}
			ecrivain.close();
		}
	}

	public void sauverMotCategorieNbDocs(){
		//System.out.println("Sauve MotCategorieNbDocs");
		// Avant de sauver le map MotCategorieNbDocs, on va gérer le cas où un mot n'apparait dans
		// aucun document

		for(String mot : motCategorieNbOccFiltre.keySet()){
			if(!motCategorieNbOccFiltre.get(mot).containsKey("positive")){				
				motCategorieNbOccFiltre.get(mot).put("positive",0.0);
			}
			if(!motCategorieNbOccFiltre.get(mot).containsKey("negative")){				
				motCategorieNbOccFiltre.get(mot).put("negative",0.0);
			}
		}

		if (sauvegarderDictionnaires){

			// Ecriture dans un fichier de sortie
			PrintWriter ecrivain = null;

			try {
				ecrivain =  new PrintWriter(new BufferedWriter
						(new FileWriter("MotCategorieNbDocs.txt")));
			} catch (IOException e) {

				e.printStackTrace();
			}

			for(String mot : motCategorieNbOccFiltre.keySet()){
				ecrivain.print(mot);
				for(String categorie : motCategorieNbOccFiltre.get(mot).keySet()){
					ecrivain.println("\t" + categorie + "----->" + motCategorieNbOccFiltre.get(mot).get(categorie));
				}
			}
			ecrivain.close();
		}
	}

	/**
	 * Cette fonction permet, à partir du nombre d'occurences de chaque mot dans
	 * chaque classe (motCategorieNbOccFiltre) et du nombre d'occurences de TOUS les mots
	 * dans chaque classe (categorieNbMotsDansToutesLesCritiquesDeLaCategorie), de déduire
	 * le paramètre Béta(mot, classe), correspondant à : 
	 * Béta(Mot,Classe) = (Nb Occurences du mot dans tous les documents de la classe) + EPSILON
	 * 															
	 * 															/
	 * 								
	 * 					(Nb Occurences de TOUS les mots de tous les documents de la classe) + EPSILON * Nombre de mots
	 * 
	 * Ici, on rajoute EPSILON au numérateur, pour éviter d'avoir des paramètres nuls. On dit
	 * qu'on utilise le lissage de Laplace.
	 * 
	 */
	public void creerEtSauvegarderMotCategorieParametre() {

		//System.out.println("Sauve motCategorieParametre");

		// Calcul du nombre total de mots dans tous les documents positifs
		categorieNbMotsDansToutesLesCritiquesDeLaCategorie.put("positive", 0.0);
		for(String mot : motCategorieNbOccFiltre.keySet()){
			categorieNbMotsDansToutesLesCritiquesDeLaCategorie.put
			("positive", categorieNbMotsDansToutesLesCritiquesDeLaCategorie.get("positive") 
					+ motCategorieNbOccFiltre.get(mot).get("positive"));
		}
		// Calcul du nombre total de mots dans tous les documents négatifs
		categorieNbMotsDansToutesLesCritiquesDeLaCategorie.put("negative", 0.0);
		for(String mot : motCategorieNbOccFiltre.keySet()){
			categorieNbMotsDansToutesLesCritiquesDeLaCategorie.put
			("negative", categorieNbMotsDansToutesLesCritiquesDeLaCategorie.get("negative") 
					+ motCategorieNbOccFiltre.get(mot).get("negative"));
		}

		// Calcul de chaque paramètre pour chaque mot, chaque catégorie
		for(String mot : motCategorieNbOccFiltre.keySet()){

			for(String categorie : motCategorieNbOccFiltre.get(mot).keySet()){

				if(!motCategorieParametre.containsKey(mot)){
					TreeMap<String, Double> categorieParametre = new TreeMap<String, Double>();
					categorieParametre.put(categorie,  (motCategorieNbOccFiltre.get(mot).get(categorie) + EPSILON) / (categorieNbMotsDansToutesLesCritiquesDeLaCategorie.get(categorie) + EPSILON*dictionnaireFiltre.size()));
					motCategorieParametre.put(mot, categorieParametre);
				}
				else {
					motCategorieParametre.get(mot).put(categorie,(motCategorieNbOccFiltre.get(mot).get(categorie) + EPSILON) / (categorieNbMotsDansToutesLesCritiquesDeLaCategorie.get(categorie) + EPSILON*dictionnaireFiltre.size()));
				}
			}
		}
	}

	/**
	 * Fonction classification() permettant ici, pour un domaine, de prendre
	 * chaque critique du fichier de test et de regarder si la logVraiSemblance
	 * la plus grande correspond bien à la polarité réelle de la critique. Si c'est
	 * le cas, c'est considéré comme une nouvelle décision correcte pour ce jeu
	 * de test. (ce qui permet de déterminer le taux de réussite)
	 */
	public void classification() {

		ArrayList<Critique> lesCritiquesAEvaluer = determinerLesCritiques(FichierTest);
		double logVraiSemblanceVraieCategorie;
		double logVraiSemblanceAutreCategorie;

		//System.out.println("Nombre critiques du fichier test : " + lesCritiquesAEvaluer.size());
		for(int i = 0; i < lesCritiquesAEvaluer.size(); i++){

			//System.out.println("Traitement critique numero " + lesCritiquesAEvaluer.get(i).getIdentifiant());
			nbCritiquesJeuDeTestCourant++;

			// Si le fichier courant est une critique positive...
			if(lesCritiquesAEvaluer.get(i).getTypeCritique().equals("positive")){

				logVraiSemblanceVraieCategorie = logVraisemblance(lesCritiquesAEvaluer.get(i).getContenu(), "positive");
				logVraiSemblanceAutreCategorie = logVraisemblance(lesCritiquesAEvaluer.get(i).getContenu(), "negative");
			}
			else {
				logVraiSemblanceVraieCategorie = logVraisemblance(lesCritiquesAEvaluer.get(i).getContenu(), "negative");
				logVraiSemblanceAutreCategorie = logVraisemblance(lesCritiquesAEvaluer.get(i).getContenu(), "positive");
			}
			if(logVraiSemblanceVraieCategorie > logVraiSemblanceAutreCategorie){
				nbDecisionsCorrectesPourUnJeuDeTest++;
			}
		}
	}

	public double logVraisemblance(String uneCritique, String categorieDuFichier){
		Map <String,Integer> motPresent = new HashMap<String, Integer>();

		double logVraisemblance = 0;
		//String categorieDuFichier = categorie;

		// Chaque mot d'une critique est séparé par un espace dans le fichier de test
		StringTokenizer tokeniseur = new StringTokenizer(uneCritique, " ");

		// Pour chaque mot trouvé sur la ligne...
		while (tokeniseur.hasMoreTokens()) {
			String motCourant = tokeniseur.nextToken();

			// Si ce n'est pas un mot outil, ni un nombre...
			// Autrement dit : si c'est un mot appartenant au dictionnaire filtré...
			if(dictionnaireFiltre.containsKey(motCourant)){
				motPresent.put(motCourant, 1);
			}
		}

		for(String mot : dictionnaireFiltre.keySet()){
			if(!motPresent.containsKey(mot)){
				motPresent.put(mot, 0);
			}
			if(motPresent.get(mot) == 1){
				logVraisemblance += Math.log(motCategorieParametre.get(mot).get(categorieDuFichier));
			}
			if(motPresent.get(mot) == 0){
				logVraisemblance += Math.log(1 - (motCategorieParametre.get(mot).get(categorieDuFichier)));
			}
		}

		return logVraisemblance;
	}

	public void sauverTauxReussite() {

		PrintWriter ecrivain = null;

		try {
			ecrivain =  new PrintWriter(new BufferedWriter
					(new FileWriter("tauxReussiteMultinomial_"+FichierTest.getParent()+".txt")));
		} catch (IOException e) {

			e.printStackTrace();
		}
		ecrivain.println("---------------------");
		ecrivain.println("Taux réussite : " + tauxReussite);
		ecrivain.close();
	}
	/**
	 * Ecrit dans un fichier CSV, pour chaque ligne, le taux de réussite
	 * en fonction de la valeur courante du seuil de filtre, du paramètre EPSILON et de la
	 * suppression (ou non) des mots outils
	 * @param ecrivain 
	 */
	public void MAJFichierCSVInfluenceSeuilFrequenceEtEpsilon(PrintWriter ecrivain){
		ecrivain.println(SUPPRESSIONMOTSOUTILS+";"+SEUIL_FREQUENCE_MAXI+";"+EPSILON+";"+dictionnaireFiltre.size()+";"+tauxReussite);
		ecrivain.flush();
	}
}
